#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;

// 定义pipefd
#define N 2

//缓冲区大小
#define NUM 1024

void Write(int wfd)
{
    // child

    //写入管道的内容
    string str = "hello I am child";
    int cnt = 0;
    pid_t self = getpid();

    //缓冲区
    char buffer[NUM];

    while(true)
    {
        buffer[0] = 0; //清空字符串'
        //将数据格式化写入到buffer
        snprintf(buffer,sizeof(buffer),"%s my pid : %d -- %d\n",str.c_str(), self,cnt++);
        cout << "child send a message "<< buffer << endl;
        //将用户缓冲区的内容拷贝到系统文件缓冲区中
        write(wfd, buffer, strlen(buffer));
        sleep(1);

        // //child
        // char c = 'c';
        // write(wfd, &c, 1);
        // cnt++;
        // if(cnt == 5) break;
        // cout << cnt << endl;
    }
}

void Read(int rfd)
{
    //father
    char buffer[NUM];
    int cnt = 0;
    //father
    while(true)
    {
        //sleep(5);
        
        //清空缓冲区，读取文件缓冲区数据到用户缓冲区
        buffer[0] = 0; // 0 == '/0'
        ssize_t n = read(rfd, buffer,sizeof(buffer));
        if(n > 0) //读取成功
        {
            buffer[n] = 0; //将缓冲区内容读上来，+'\0'表示当做字符串使用
            cout << "father get a message" << "father's pid : " << getpid() << "  " << buffer << endl;
        } 
        else if(n == 0)// read done
        {
            cout << "father read done!";
            break;
        }
        else // error
            break;

        cnt++; //读取5次直接关闭读端
        if(cnt > 5)
        {
            break;
        }
    }

}

int main()
{
    //创建管道
    int pipefd[N] = {0};
    
    int n  = pipe(pipefd);
    if(n == -1) // 创建失败
        return n;
    
    //简单验证一下输出型参数pipefd
    //cout << "pipefd[0]: " << pipefd[0] << "pipefd[1]: " << pipefd[1] << endl;

    // 创建子进程并使用管道通信
    // father --> read    child --> write
    //fork创建子进程
    pid_t id = fork();
    if(id < 0)//创建失败
        return 2; 
    if(id == 0) // child
    {
        //关闭对应的读端
        close(pipefd[0]);

        // 进行通信，然后关闭fd并退出
        Write(pipefd[1]);

        close(pipefd[1]);
        exit(0); 
    }
    //father
    //关闭对应的写端
    close(pipefd[1]);

    //调用定义的读方法
    Read(pipefd[0]); 
    close(pipefd[0]); // 读取5次关闭读端
    cout << "father close read fd : " << pipefd[0] << endl;
    sleep(5); // 为了观察子进程僵尸状态

    //等待子进程
    int status = 0; 
    pid_t rid = waitpid(id, &status, 0);
    if(rid < 0) //error
        return 3;
    
    cout << "child wait success : " << rid << "exit code : " << ((status >> 8) & 0xFF) 
    << " exit signal :" << (status & 0x7F) << endl;

    sleep(5); 
    cout << "father quit!" << endl; 
    return 0;
}